from abc import ABC, abstractmethod
import textwrap
class AlertEvent(ABC):

    @property
    @abstractmethod
    def event_name(self)->str:
        pass

    @property
    @abstractmethod
    def event_content(self)->str:
        pass

    @abstractmethod
    def alert(self,status_info,ip_info,log_info)->bool:
        pass

    def _format_logs(self, log_info, max_lines=10) -> str:
        """格式化日志信息，限制显示行数并添加省略提示"""
        if not log_info:
            return "无日志信息"

        # 确保日志是字符串列表，统一格式
        formatted_logs = [str(log) for log in log_info]
        log_count = len(formatted_logs)

        # 截取前N行日志
        display_logs = formatted_logs[:max_lines]
        logs_str = "\n".join([f"[{i + 1}] {log}" for i, log in enumerate(display_logs)])

        # 添加省略提示（如果日志过多）
        if log_count > max_lines:
            logs_str += f"\n... 省略 {log_count - max_lines} 条日志（共 {log_count} 条）"

        return logs_str

class ErrorEvent(AlertEvent):
    def __init__(self,max_error_rate = 0.5,min_total = 10):
        self.max_error_rate = max_error_rate
        self.min_total = min_total
        self.content = None

    @property
    def event_name(self) ->str:
        return '错误事件警告'

    @property
    def event_content(self) -> str:
        return self.content

    def alert(self, status_info, ip_info, log_info) -> bool:
        total = len(log_info)

        # 请求总量未达到最小报警阈值，直接返回
        if total <= self.min_total:
            return False
        # 统计错误状态码数量
        error_count = 0
        error_status = []  # 记录错误状态码及其数量
        for status_code, count in status_info.items():
            if status_code >= 400:
                error_count += count
                error_status.append(f"状态码 {status_code}: {count} 次")

        # 计算错误率并判断是否需要报警
        error_rate = error_count / total if total > 0 else 0
        if error_rate >= self.max_error_rate:
            # 格式化错误率为百分比
            error_rate_percent = f"{error_rate:.2%}"
            formatted_logs = self._format_logs(log_info)

            self.content = textwrap.dedent(f"""
⚠️ 服务器请求错误率警报 ⚠️

🔴 触发条件：错误率超过阈值
├─ 当前错误率：{error_rate_percent}
├─ 阈值设定：{self.max_error_rate:.2%}
├─ 总请求量：{total} 次
└─ 错误请求量：{error_count} 次

📊 错误状态码分布：
{chr(10).join(error_status)}

📋 相关日志片段（按时间顺序）：
{formatted_logs}

⚡ 建议行动：
1. 检查错误状态码集中的请求类型
2. 分析高频错误IP的请求特征
3. 确认服务是否存在功能性故障
                        """).strip()
            return True

        return False

class IpEvent(AlertEvent):
    def __init__(self,max_ip_access=60):
        self.max_ip_access = max_ip_access
        self.content = None

    @property
    def event_name(self) -> str:
        return 'ip请求频繁事件警告'

    @property
    def event_content(self) -> str:
        return self.content

    def alert(self, status_info, ip_info, log_info) -> bool:
        for ip, count in ip_info.items():
            if count > self.max_ip_access:
                # 筛选该IP的相关日志
                ip_logs = [log for log in log_info if ip in str(log)]
                formatted_logs = self._format_logs(ip_logs)

                self.content = textwrap.dedent(f"""
⚠️ IP请求频繁警报 ⚠️

🔴 触发条件：单IP请求量超过阈值
├─ 异常IP：{ip}
├─ 请求次数：{count} 次
└─ 阈值设定：{self.max_ip_access} 次

📋 该IP相关日志片段：
{formatted_logs}

⚡ 建议行动：
1. 确认是否为正常业务峰值
2. 检查该IP是否存在恶意请求特征
3. 考虑临时限制该IP访问频率
                """).strip()
                return True
        return False


class ServerErrorEvent(AlertEvent):
    def __init__(self,max_server_error=5):
        self.max_server_error = max_server_error
        self.content = None

    @property
    def event_name(self) -> str:
        return '服务器错误事件警报'

    @property
    def event_content(self) -> str:
        return self.content

    def alert(self, status_info, ip_info, log_info) -> bool:
        error_count = 0
        error_status = []
        for status_code, count in status_info.items():
            if status_code >= 500:
                error_count += count
                error_status.append(f"• 状态码 {status_code}: {count} 次")

        if error_count >= self.max_server_error:
            # 筛选5xx错误的相关日志
            server_error_logs = [log for log in log_info if any(
                f" {code} " in str(log) for code in status_info if code >= 500
            )]
            formatted_logs = self._format_logs(server_error_logs)

            self.content = textwrap.dedent(f"""
⚠️ 服务器错误事件警报 ⚠️

🔴 触发条件：5xx错误数量超过阈值
├─ 错误总量：{error_count} 次
├─ 阈值设定：{self.max_server_error} 次
└─ 总请求量：{len(log_info)} 次

📊 错误状态码分布：
{chr(10).join(error_status)}

📋 服务器错误相关日志片段：
{formatted_logs}

⚡ 建议行动：
1. 检查应用服务器运行状态
2. 查看数据库连接是否正常
3. 分析错误日志中的堆栈信息
4. 考虑临时切换到备用服务器
            """).strip()
            return True

        return False
